path = "src/cargo/lib.rs"
# TODO: remove all these `rev` markers once we have an official lockfile
-[dependencies.hammer]
-git = "https://github.com/wycats/hammer.rs"
-rev = "c085c639"
+[dependencies.docopt]
+git = "https://github.com/burntsushi/docopt.rs"
+rev = "0babd54a"
+
+[dependencies.docopt_macros]
+git = "https://github.com/burntsushi/docopt.rs"
+rev = "0babd54a"
[dependencies.toml]
git = "https://github.com/alexcrichton/toml-rs"
-#![crate_name="cargo-build"]
#![feature(phase)]
-extern crate cargo;
-
-#[phase(plugin, link)]
-extern crate hammer;
-
-#[phase(plugin, link)]
-extern crate log;
-
extern crate serialize;
+#[phase(plugin, link)] extern crate log;
+
+extern crate cargo;
+extern crate docopt;
+#[phase(plugin)] extern crate docopt_macros;
use std::os;
use cargo::{execute_main_without_stdin};
use cargo::util::{CliResult, CliError};
use cargo::util::important_paths::{find_root_manifest_for_cwd};
-#[deriving(PartialEq,Clone,Decodable,Encodable)]
-pub struct Options {
- manifest_path: Option<String>,
- update_remotes: bool,
- jobs: Option<uint>,
- target: Option<String>,
- release: bool,
-}
+docopt!(Options, "
+Compile a local package and all of its dependencies
+
+Usage:
+ cargo-build [options]
-hammer_config!(Options "Build the current project", |c| {
- c.short("update_remotes", 'u')
- .short("jobs", 'j')
-})
+Options:
+ -h, --help Print this message
+ -j N, --jobs N The number of jobs to run in parallel
+ --release Build artifacts in release mode, with optimizations
+ --target TRIPLE Build for the target triple
+ -u, --update-remotes Update all remote packages before compiling
+ --manifest-path PATH Path to the manifest to compile
+ -v, --verbose Use verbose output
+", flag_jobs: Option<uint>, flag_target: Option<String>,
+ flag_manifest_path: Option<String>)
fn main() {
- execute_main_without_stdin(execute);
+ execute_main_without_stdin(execute, false);
}
fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
debug!("executing; cmd=cargo-compile; args={}", os::args());
+ shell.set_verbose(options.flag_verbose);
- let root = try!(find_root_manifest_for_cwd(options.manifest_path));
+ let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));
- let env = if options.release {
+ let env = if options.flag_release {
"release"
} else {
"compile"
};
let mut opts = CompileOptions {
- update: options.update_remotes,
+ update: options.flag_update_remotes,
env: env,
shell: shell,
- jobs: options.jobs,
- target: options.target.as_ref().map(|t| t.as_slice()),
+ jobs: options.flag_jobs,
+ target: options.flag_target.as_ref().map(|t| t.as_slice()),
};
ops::compile(&root, &mut opts).map(|_| None).map_err(|err| {
-#![crate_name="cargo-clean"]
#![feature(phase)]
-extern crate cargo;
-
-#[phase(plugin, link)]
-extern crate hammer;
-
-#[phase(plugin, link)]
-extern crate log;
-
extern crate serialize;
+#[phase(plugin, link)] extern crate log;
+
+extern crate cargo;
+extern crate docopt;
+#[phase(plugin)] extern crate docopt_macros;
use std::os;
use cargo::ops;
use cargo::util::{CliResult, CliError};
use cargo::util::important_paths::{find_root_manifest_for_cwd};
-#[deriving(PartialEq,Clone,Decodable,Encodable)]
-pub struct Options {
- manifest_path: Option<String>
-}
+docopt!(Options, "
+Usage:
+ cargo-clean [options]
-hammer_config!(Options)
+Options:
+ -h, --help Print this message
+ --manifest-path PATH Path to the manifest to compile
+ -v, --verbose Use verbose output
+", flag_manifest_path: Option<String>)
fn main() {
- execute_main_without_stdin(execute);
+ execute_main_without_stdin(execute, false);
}
fn execute(options: Options, _shell: &mut MultiShell) -> CliResult<Option<()>> {
debug!("executing; cmd=cargo-clean; args={}", os::args());
- let root = try!(find_root_manifest_for_cwd(options.manifest_path));
+ let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));
ops::clean(&root).map(|_| None).map_err(|err| {
CliError::from_boxed(err, 101)
#![feature(phase)]
-#[phase(plugin, link)]
-extern crate cargo;
extern crate serialize;
-
-#[phase(plugin, link)]
-extern crate hammer;
+extern crate cargo;
+extern crate docopt;
+#[phase(plugin)] extern crate docopt_macros;
use std::os;
use cargo::util::{CliResult, CliError};
use cargo::util::important_paths::find_project_manifest;
-#[deriving(PartialEq,Clone,Decodable)]
-struct Options {
- manifest_path: Option<String>,
- jobs: Option<uint>,
- update: bool,
- no_deps: bool,
-}
+docopt!(Options, "
+Build a package's documentation
+
+Usage:
+ cargo-doc [options]
+
+Options:
+ -h, --help Print this message
+ --no-deps Don't build documentation for dependencies
+ -j N, --jobs N The number of jobs to run in parallel
+ -u, --update-remotes Update all remote packages before compiling
+ --manifest-path PATH Path to the manifest to compile
+ -v, --verbose Use verbose output
-hammer_config!(Options "Build the package's documentation", |c| {
- c.short("jobs", 'j').short("update", 'u')
-})
+By default the documentation for the local package and all dependencies is
+built. The output is all placed in `target/doc` in rustdoc's usual format.
+", flag_jobs: Option<uint>,
+ flag_manifest_path: Option<String>)
fn main() {
- execute_main_without_stdin(execute);
+ execute_main_without_stdin(execute, false)
}
fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
- let root = match options.manifest_path {
+ shell.set_verbose(options.flag_verbose);
+ let root = match options.flag_manifest_path {
Some(path) => Path::new(path),
None => try!(find_project_manifest(&os::getcwd(), "Cargo.toml")
.map_err(|_| {
};
let mut doc_opts = ops::DocOptions {
- all: !options.no_deps,
+ all: !options.flag_no_deps,
compile_opts: ops::CompileOptions {
- update: options.update,
- env: if options.no_deps {"doc"} else {"doc-all"},
+ update: options.flag_update_remotes,
+ env: if options.flag_no_deps {"doc"} else {"doc-all"},
shell: shell,
- jobs: options.jobs,
+ jobs: options.flag_jobs,
target: None,
},
};
-#![crate_name="cargo-git-checkout"]
#![feature(phase)]
-extern crate cargo;
extern crate serialize;
extern crate url;
+#[phase(plugin, link)] extern crate log;
-#[phase(plugin, link)]
-extern crate hammer;
+extern crate cargo;
+extern crate docopt;
+#[phase(plugin)] extern crate docopt_macros;
use cargo::{execute_main_without_stdin};
use cargo::core::MultiShell;
use cargo::util::{Config, CliResult, CliError, Require, human};
use url::Url;
-#[deriving(PartialEq,Clone,Decodable)]
-struct Options {
- url: String,
- reference: String
-}
+docopt!(Options, "
+Usage:
+ cargo-git-checkout [options] --url=URL --reference=REF
-hammer_config!(Options)
+Options:
+ -h, --help Print this message
+ -v, --verbose Use verbose output
+")
fn main() {
- execute_main_without_stdin(execute);
+ execute_main_without_stdin(execute, false);
}
fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
- let Options { url, reference, .. } = options;
+ let Options { flag_url: url, flag_reference: reference, .. } = options;
let url: Url = try!(from_str(url.as_slice())
.require(|| human(format!("The URL `{}` you passed was \
#![feature(phase)]
-extern crate cargo;
-
-#[phase(plugin, link)]
-extern crate hammer;
-
-#[phase(plugin, link)]
-extern crate log;
-
extern crate serialize;
+extern crate cargo;
+extern crate docopt;
+#[phase(plugin)] extern crate docopt_macros;
+#[phase(plugin, link)] extern crate log;
use std::os;
use cargo::ops;
use cargo::core::MultiShell;
use cargo::util::{CliResult, CliError};
-#[deriving(PartialEq,Clone,Decodable,Encodable)]
-pub struct Options {
- git: bool,
- bin: bool,
- rest: Vec<String>,
-}
+docopt!(Options, "
+Create a new cargo package at <path>
+
+Usage:
+ cargo-new [options] <path>
+ cargo-new -h | --help
-hammer_config!(Options "Create a new cargo project")
+Options:
+ -h, --help Print this message
+ --git Initialize a new git repository with a .gitignore
+ --bin Use a binary instead of a library template
+ -v, --verbose Use verbose output
+")
fn main() {
- cargo::execute_main_without_stdin(execute);
+ cargo::execute_main_without_stdin(execute, false)
}
fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
debug!("executing; cmd=cargo-new; args={}", os::args());
+ shell.set_verbose(options.flag_verbose);
- let Options { git, mut rest, bin } = options;
-
- let path = match rest.remove(0) {
- Some(path) => path,
- None => return Err(CliError::new("must have a path as an argument", 1))
- };
+ let Options { flag_git, flag_bin, arg_path, .. } = options;
let opts = ops::NewOptions {
- git: git,
- path: path.as_slice(),
- bin: bin,
+ git: flag_git,
+ path: arg_path.as_slice(),
+ bin: flag_bin,
};
ops::new(opts, shell).map(|_| None).map_err(|err| {
-#![crate_name="cargo-read-manifest"]
#![feature(phase)]
-extern crate cargo;
extern crate serialize;
-
-#[phase(plugin, link)]
-extern crate hammer;
+extern crate cargo;
+extern crate docopt;
+#[phase(plugin)] extern crate docopt_macros;
use cargo::{execute_main_without_stdin};
use cargo::core::{MultiShell, Package, Source};
use cargo::util::{CliResult, CliError};
use cargo::sources::{PathSource};
-#[deriving(PartialEq,Clone,Decodable)]
-struct Options {
- manifest_path: String
-}
+docopt!(Options, "
+Usage:
+ cargo-clean [options] --manifest-path=PATH
-hammer_config!(Options)
+Options:
+ -h, --help Print this message
+ -v, --verbose Use verbose output
+")
fn main() {
- execute_main_without_stdin(execute);
+ execute_main_without_stdin(execute, false);
}
fn execute(options: Options, _: &mut MultiShell) -> CliResult<Option<Package>> {
- let mut source = PathSource::for_path(&Path::new(options.manifest_path.as_slice()));
+ let path = Path::new(options.flag_manifest_path.as_slice());
+ let mut source = PathSource::for_path(&path);
try!(source.update().map_err(|err| CliError::new(err.description(), 1)));
#![feature(phase)]
-#[phase(plugin, link)]
-extern crate cargo;
extern crate serialize;
-
-#[phase(plugin, link)]
-extern crate hammer;
+extern crate cargo;
+extern crate docopt;
+#[phase(plugin)] extern crate docopt_macros;
use std::io::process::ExitStatus;
use cargo::util::{CliResult, CliError};
use cargo::util::important_paths::{find_root_manifest_for_cwd};
-#[deriving(PartialEq,Clone,Decodable)]
-struct Options {
- manifest_path: Option<String>,
- jobs: Option<uint>,
- update: bool,
- rest: Vec<String>,
-}
+docopt!(Options, "
+Run the main binary of the local package (src/main.rs)
+
+Usage:
+ cargo-run [options] [--] [<args>...]
+
+Options:
+ -h, --help Print this message
+ -j N, --jobs N The number of jobs to run in parallel
+ -u, --update-remotes Update all remote packages before compiling
+ --manifest-path PATH Path to the manifest to compile
+ -v, --verbose Use verbose output
-hammer_config!(Options "Run the package's main executable", |c| {
- c.short("jobs", 'j').short("update", 'u')
-})
+All of the trailing arguments are passed as to the binary to run.
+", flag_jobs: Option<uint>, flag_target: Option<String>,
+ flag_manifest_path: Option<String>)
fn main() {
- execute_main_without_stdin(execute);
+ execute_main_without_stdin(execute, true);
}
fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
- let root = try!(find_root_manifest_for_cwd(options.manifest_path));
+ let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));
+ shell.set_verbose(options.flag_verbose);
let mut compile_opts = ops::CompileOptions {
- update: options.update,
+ update: options.flag_update_remotes,
env: "compile",
shell: shell,
- jobs: options.jobs,
+ jobs: options.flag_jobs,
target: None,
};
let err = try!(ops::run(&root, &mut compile_opts,
- options.rest.as_slice()).map_err(|err| {
+ options.arg_args.as_slice()).map_err(|err| {
CliError::from_boxed(err, 101)
}));
match err {
-#![crate_name="cargo-rustc"]
-
extern crate cargo;
fn main() {
-#![crate_name="cargo-test"]
#![feature(phase)]
-#[phase(plugin, link)]
-extern crate cargo;
extern crate serialize;
-
-#[phase(plugin, link)]
-extern crate hammer;
+extern crate cargo;
+extern crate docopt;
+#[phase(plugin)] extern crate docopt_macros;
use std::io::process::ExitStatus;
use cargo::util::{CliResult, CliError, CargoError};
use cargo::util::important_paths::{find_root_manifest_for_cwd};
-#[deriving(PartialEq,Clone,Decodable)]
-struct Options {
- manifest_path: Option<String>,
- jobs: Option<uint>,
- update: bool,
- rest: Vec<String>,
-}
+docopt!(Options, "
+Execute all unit and integration tests of a local package
+
+Usage:
+ cargo-test [options] [--] [<args>...]
+
+Options:
+ -h, --help Print this message
+ -j N, --jobs N The number of jobs to run in parallel
+ -u, --update-remotes Update all remote packages before compiling
+ --manifest-path PATH Path to the manifest to compile
+ -v, --verbose Use verbose output
-hammer_config!(Options "Run the package's test suite", |c| {
- c.short("jobs", 'j').short("update", 'u')
-})
+All of the trailing arguments are passed to the test binaries generated for
+filtering tests and generally providing options configuring how they run.
+", flag_jobs: Option<uint>, flag_target: Option<String>,
+ flag_manifest_path: Option<String>)
fn main() {
- execute_main_without_stdin(execute);
+ execute_main_without_stdin(execute, true);
}
fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
- let root = try!(find_root_manifest_for_cwd(options.manifest_path));
+ let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));
+ shell.set_verbose(options.flag_verbose);
let mut compile_opts = ops::CompileOptions {
- update: options.update,
+ update: options.flag_update_remotes,
env: "test",
shell: shell,
- jobs: options.jobs,
+ jobs: options.flag_jobs,
target: None,
};
for file in test_executables.iter() {
try!(util::process(test_dir.join(file.as_slice()))
- .args(options.rest.as_slice())
+ .args(options.arg_args.as_slice())
.exec().map_err(|e| {
let exit_status = match e.exit {
Some(ExitStatus(i)) => i as uint,
-#![crate_name="cargo-version"]
#![feature(phase)]
-extern crate cargo;
-
-#[phase(plugin, link)]
-extern crate hammer;
-
-#[phase(plugin, link)]
-extern crate log;
-
extern crate serialize;
+extern crate cargo;
+extern crate docopt;
+#[phase(plugin)] extern crate docopt_macros;
+#[phase(plugin, link)] extern crate log;
use std::os;
use cargo::execute_main_without_stdin;
use cargo::core::MultiShell;
use cargo::util::CliResult;
-#[deriving(Decodable,Encodable)]
-pub struct Options;
+docopt!(Options, "
+Usage:
+ cargo-version [options]
-hammer_config!(Options)
+Options:
+ -h, --help Print this message
+ -v, --verbose Use verbose output
+")
-
fn main() {
- execute_main_without_stdin(execute);
+ execute_main_without_stdin(execute, false);
}
fn execute(_: Options, _: &mut MultiShell) -> CliResult<Option<()>> {
#![feature(phase)]
-extern crate cargo;
-#[phase(plugin, link)]
-extern crate hammer;
-
extern crate serialize;
+#[phase(plugin, link)] extern crate log;
-#[phase(plugin, link)]
-extern crate log;
+extern crate cargo;
+extern crate docopt;
+#[phase(plugin)] extern crate docopt_macros;
-use hammer::{FlagConfig,FlagConfiguration};
use std::os;
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
-use cargo::{GlobalFlags, NoFlags, execute_main_without_stdin, handle_error, shell};
+use docopt::FlagParser;
+
+use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::important_paths::find_project;
use cargo::util::{CliError, CliResult, Require, config, human};
fn main() {
- execute();
+ execute_main_without_stdin(execute, true)
}
-#[deriving(Encodable)]
-struct ProjectLocation {
- root: String
-}
+docopt!(Flags, "
+Rust's package manager
+
+Usage:
+ cargo <command> [<args>...]
+ cargo -h | --help
+ cargo -V | --version
+
+Options:
+ -h, --help Display this message
+ -V, --version Print version info and exit
+ -v, --verbose Use verbose output
+
+Some common cargo commands are:
+ build Compile the current project
+ clean Remove the target directory
+ doc Build this project's and its dependencies' documentation
+ new Create a new cargo project
+ run Build and execute src/main.rs
+ test Run the tests
+
+See 'cargo help <command>' for more information on a specific command.
+")
/**
The top-level `cargo` command handles configuration and project location
because they are fundamental (and intertwined). Other commands can rely
on this top-level information.
*/
-fn execute() {
+fn execute(flags: Flags, shell: &mut MultiShell) -> CliResult<Option<()>> {
debug!("executing; cmd=cargo; args={}", os::args());
- let (cmd, args) = process(os::args());
-
- match cmd.as_slice() {
+ shell.set_verbose(flags.flag_verbose);
+ let mut args = flags.arg_args.clone();
+ args.insert(0, flags.arg_command.clone());
+ match flags.arg_command.as_slice() {
"config-for-key" => {
log!(4, "cmd == config-for-key");
- execute_main_without_stdin(config_for_key)
+ let r = cargo::call_main_without_stdin(config_for_key, shell,
+ args.as_slice(), false);
+ cargo::process_executed(r, shell)
},
"config-list" => {
log!(4, "cmd == config-list");
- execute_main_without_stdin(config_list)
+ let r = cargo::call_main_without_stdin(config_list, shell,
+ args.as_slice(), false);
+ cargo::process_executed(r, shell)
},
"locate-project" => {
log!(4, "cmd == locate-project");
- execute_main_without_stdin(locate_project)
+ let r = cargo::call_main_without_stdin(locate_project, shell,
+ args.as_slice(), false);
+ cargo::process_executed(r, shell)
},
- "--help" | "-h" | "help" | "-?" => {
- println!("Commands:");
- println!(" build # compile the current project");
- println!(" test # run the tests");
- println!(" clean # remove the target directory");
- println!(" run # build and execute src/main.rs");
- println!(" version # displays the version of cargo");
- println!(" new # create a new cargo project");
- println!(" doc # build project's rustdoc documentation");
- println!("");
-
-
- let (_, options) = hammer::usage::<GlobalFlags>(false);
- println!("Options (for all commands):\n\n{}", options);
- },
- _ => {
- // `cargo --version` and `cargo -v` are aliases for `cargo version`
- let cmd = if cmd.as_slice() == "--version" || cmd.as_slice() == "-V" {
- "version".into_string()
+ // If we have `help` with no arguments, re-invoke ourself with `-h` to
+ // get the help message printed
+ "help" if flags.arg_args.len() == 0 => {
+ shell.set_verbose(true);
+ let r = cargo::call_main_without_stdin(execute, shell,
+ ["-h".to_string()], false);
+ cargo::process_executed(r, shell)
+ }
+ orig_cmd => {
+ let cmd = if orig_cmd == "help" {
+ flags.arg_args[0].as_slice()
} else {
- cmd
+ orig_cmd
};
let command = format!("cargo-{}{}", cmd, os::consts::EXE_SUFFIX);
let mut command = match os::self_exe_path() {
}
None => Command::new(command),
};
- let command = command
- .args(args.as_slice())
+ let command = if orig_cmd == "help" {
+ command.arg("-h")
+ } else {
+ command.args(flags.arg_args.as_slice())
+ };
+ let status = command
.stdin(InheritFd(0))
.stdout(InheritFd(1))
.stderr(InheritFd(2))
.status();
- match command {
+ match status {
Ok(ExitStatus(0)) => (),
Ok(ExitStatus(i)) => {
- handle_error(CliError::new("", i as uint), &mut shell(false))
+ handle_error(CliError::new("", i as uint), shell)
}
Ok(ExitSignal(i)) => {
let msg = format!("subcommand failed with signal: {}", i);
- handle_error(CliError::new(msg, 1), &mut shell(false))
+ handle_error(CliError::new(msg, i as uint), shell)
}
- Err(_) => handle_error(CliError::new("No such subcommand", 127), &mut shell(false))
+ Err(_) => handle_error(CliError::new("No such subcommand", 127),
+ shell)
}
}
}
-}
-
-fn process(args: Vec<String>) -> (String, Vec<String>) {
- let mut args = Vec::from_slice(args.tail());
- let head = args.remove(0).unwrap_or("--help".to_string());
-
- (head, args)
+ Ok(None)
}
#[deriving(Encodable)]
values: std::collections::HashMap<String, config::ConfigValue>
}
-#[deriving(Decodable)]
-struct ConfigForKeyFlags {
- key: String,
- human: bool
-}
+docopt!(ConfigForKeyFlags, "
+Usage: cargo config-for-key --human --key=<key>
+")
-impl FlagConfig for ConfigForKeyFlags {
- fn config(_: Option<ConfigForKeyFlags>,
- config: FlagConfiguration) -> FlagConfiguration {
- config.short("human", 'h')
- }
-}
-
-fn config_for_key(args: ConfigForKeyFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
+fn config_for_key(args: ConfigForKeyFlags,
+ _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
let value = try!(config::get_config(os::getcwd(),
- args.key.as_slice()).map_err(|_| {
+ args.flag_key.as_slice()).map_err(|_| {
CliError::new("Couldn't load configuration", 1)
}));
- if args.human {
+ if args.flag_human {
println!("{}", value);
Ok(None)
} else {
let mut map = std::collections::HashMap::new();
- map.insert(args.key.clone(), value);
+ map.insert(args.flag_key.clone(), value);
Ok(Some(ConfigOut { values: map }))
}
}
-#[deriving(Decodable)]
-struct ConfigListFlags {
- human: bool
-}
-
-impl FlagConfig for ConfigListFlags {
- fn config(_: Option<ConfigListFlags>,
- config: FlagConfiguration) -> FlagConfiguration {
- config.short("human", 'h')
- }
-}
+docopt!(ConfigListFlags, "
+Usage: cargo config-list --human
+")
fn config_list(args: ConfigListFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
let configs = try!(config::all_configs(os::getcwd()).map_err(|_|
CliError::new("Couldn't load configuration", 1)));
- if args.human {
+ if args.flag_human {
for (key, value) in configs.iter() {
println!("{} = {}", key, value);
}
}
}
-fn locate_project(_: NoFlags, _: &mut MultiShell) -> CliResult<Option<ProjectLocation>> {
+docopt!(LocateProjectFlags, "
+Usage: cargo locate-project
+")
+
+#[deriving(Encodable)]
+struct ProjectLocation {
+ root: String
+}
+
+fn locate_project(_: LocateProjectFlags,
+ _: &mut MultiShell) -> CliResult<Option<ProjectLocation>> {
let root = try!(find_project(&os::getcwd(), "Cargo.toml").map_err(|e| {
CliError::from_boxed(e, 1)
}));
pub fn warn<T: ToString>(&mut self, message: T) -> IoResult<()> {
self.err().say(message, YELLOW)
}
+
+ pub fn set_verbose(&mut self, verbose: bool) {
+ self.verbose = verbose;
+ }
}
pub type ShellCallback<'a> = |&mut Shell|:'a -> IoResult<()>;
extern crate url;
extern crate serialize;
extern crate semver;
-extern crate toml;
-
-#[phase(plugin, link)]
-extern crate hammer;
+#[phase(plugin, link)] extern crate log;
-#[phase(plugin, link)]
-extern crate log;
-
-#[cfg(test)]
-extern crate hamcrest;
+extern crate toml;
+extern crate docopt;
+#[cfg(test)] extern crate hamcrest;
-use serialize::{Decoder, Encoder, Decodable, Encodable, json};
-use std::io;
-use std::io::{stdout, stderr};
+use std::os;
use std::io::stdio::{stdout_raw, stderr_raw};
-use hammer::{Flags, decode_args, usage};
+use std::io::{stdout, stderr};
+use std::io;
+use serialize::{Decoder, Encoder, Decodable, Encodable, json};
+use docopt::FlagParser;
use core::{Shell, MultiShell, ShellConfig};
use term::color::{BLACK};
trait RepresentsJSON : Decodable<json::Decoder, json::DecoderError> {}
impl<T: Decodable<json::Decoder, json::DecoderError>> RepresentsJSON for T {}
-#[deriving(Decodable)]
-pub struct NoFlags;
-
-hammer_config!(NoFlags)
-
-#[deriving(Show, Decodable)]
-pub struct GlobalFlags {
- verbose: bool,
- help: bool,
- rest: Vec<String>
-}
-
-hammer_config!(GlobalFlags |c| {
- c.short("verbose", 'v').short("help", 'h')
-})
-
pub fn execute_main<'a,
- T: Flags,
+ T: FlagParser,
U: RepresentsJSON,
V: Encodable<json::Encoder<'a>, io::IoError>>(
- exec: fn(T, U, &mut MultiShell) -> CliResult<Option<V>>) {
- fn call<'a,
- T: Flags,
- U: RepresentsJSON,
- V: Encodable<json::Encoder<'a>, io::IoError>>(
- exec: fn(T, U, &mut MultiShell) -> CliResult<Option<V>>,
- shell: &mut MultiShell,
- args: &[String]) -> CliResult<Option<V>> {
- let flags = try!(flags_from_args::<T>(args));
- let json = try!(json_from_stdin::<U>());
-
- exec(flags, json, shell)
- }
+ exec: fn(T, U, &mut MultiShell) -> CliResult<Option<V>>,
+ options_first: bool) {
+ process::<V>(|rest, shell| call_main(exec, shell, rest, options_first));
+}
- process::<T, V>(|rest, shell| call(exec, shell, rest));
+pub fn call_main<'a,
+ T: FlagParser,
+ U: RepresentsJSON,
+ V: Encodable<json::Encoder<'a>, io::IoError>>(
+ exec: fn(T, U, &mut MultiShell) -> CliResult<Option<V>>,
+ shell: &mut MultiShell,
+ args: &[String],
+ options_first: bool) -> CliResult<Option<V>> {
+ let flags = try!(flags_from_args::<T>(args, options_first));
+ let json = try!(json_from_stdin::<U>());
+
+ exec(flags, json, shell)
}
pub fn execute_main_without_stdin<'a,
- T: Flags,
+ T: FlagParser,
V: Encodable<json::Encoder<'a>, io::IoError>>(
- exec: fn(T, &mut MultiShell) -> CliResult<Option<V>>) {
- fn call<'a,
- T: Flags,
- V: Encodable<json::Encoder<'a>, io::IoError>>(
- exec: fn(T, &mut MultiShell) -> CliResult<Option<V>>,
- shell: &mut MultiShell,
- args: &[String]) -> CliResult<Option<V>> {
- let flags = try!(flags_from_args::<T>(args));
- exec(flags, shell)
- }
+ exec: fn(T, &mut MultiShell) -> CliResult<Option<V>>,
+ options_first: bool) {
+ process::<V>(|rest, shell| call_main_without_stdin(exec, shell, rest,
+ options_first));
+}
- process::<T, V>(|rest, shell| call(exec, shell, rest));
+pub fn call_main_without_stdin<'a,
+ T: FlagParser,
+ V: Encodable<json::Encoder<'a>, io::IoError>>(
+ exec: fn(T, &mut MultiShell) -> CliResult<Option<V>>,
+ shell: &mut MultiShell,
+ args: &[String],
+ options_first: bool) -> CliResult<Option<V>> {
+ let flags = try!(flags_from_args::<T>(args, options_first));
+ exec(flags, shell)
}
-fn process<'a,
- T: Flags,
- V: Encodable<json::Encoder<'a>, io::IoError>>(
+fn process<'a, V: Encodable<json::Encoder<'a>, io::IoError>>(
callback: |&[String], &mut MultiShell| -> CliResult<Option<V>>) {
-
-
- match global_flags() {
- Err(e) => handle_error(e, &mut shell(false)),
- Ok(val) => {
- let mut shell = shell(val.verbose);
-
- if val.help {
- let (desc, options) = usage::<T>(true);
-
- desc.map(|d| println!("{}\n", d));
-
- println!("Options:\n");
-
- print!("{}", options);
-
- let (_, options) = usage::<GlobalFlags>(false);
- print!("{}", options);
- } else {
- process_executed(callback(val.rest.as_slice(), &mut shell), &mut shell)
- }
- }
- }
+ let mut shell = shell(true);
+ let mut args = os::args();
+ args.remove(0);
+ process_executed(callback(args.as_slice(), &mut shell), &mut shell)
}
pub fn process_executed<'a,
pub fn handle_error(err: CliError, shell: &mut MultiShell) {
log!(4, "handle_error; err={}", err);
- let CliError { error, exit_code, unknown, .. } = err;
+ let CliError { error, exit_code, unknown } = err;
if unknown {
let _ = shell.error("An unknown error occurred");
- } else {
+ } else if error.to_string().len() > 0 {
let _ = shell.error(error.to_string());
}
if unknown {
let _ = shell.error(error.to_string());
}
+ error.detail().map(|detail| {
+ let _ = shell.err().say(format!("{}", detail), BLACK);
+ });
error.cause().map(|err| {
let _ = handle_cause(err, shell);
});
err.cause().map(|e| handle_cause(e, shell));
}
-fn args() -> Vec<String> {
- std::os::args()
-}
-
-fn flags_from_args<T: Flags>(args: &[String]) -> CliResult<T> {
- decode_args(args).map_err(|e| {
- CliError::new(e.message, 1)
- })
+pub fn version() -> String {
+ (env!("CFG_VERSION")).to_string()
}
-fn global_flags() -> CliResult<GlobalFlags> {
- decode_args(args().tail()).map_err(|e| {
- CliError::new(e.message, 1)
+fn flags_from_args<T: FlagParser>(args: &[String],
+ options_first: bool) -> CliResult<T> {
+ let args = args.iter().map(|a| a.as_slice()).collect::<Vec<&str>>();
+ let config = docopt::Config {
+ options_first: options_first,
+ help: true,
+ version: Some(version()),
+ };
+ FlagParser::parse_args(config, args.as_slice()).map_err(|e| {
+ let code = if e.fatal() {1} else {0};
+ CliError::from_error(e, code)
})
}
use std::collections::{HashMap, HashSet};
-use std::os;
use std::str;
use core::{SourceMap, Package, PackageId, PackageSet, Resolve, Target};
use std::fmt::{Show, Formatter, FormatError};
use std::str;
+use docopt;
use TomlError = toml::Error;
pub trait CargoError: Send {
fn description(&self) -> String;
fn detail(&self) -> Option<String> { None }
- fn cause(&self) -> Option<&CargoError + Send> { None }
+ fn cause(&self) -> Option<&CargoError> { None }
fn is_human(&self) -> bool { false }
fn to_error<E: FromError<Self>>(self) -> E {
(*self).detail()
}
- fn cause(&self) -> Option<&CargoError + Send> {
+ fn cause(&self) -> Option<&CargoError> {
(*self).cause()
}
self.detail.clone()
}
- fn cause(&self) -> Option<&CargoError + Send> {
- self.cause.as_ref().map(|c| { let err: &CargoError + Send = *c; err })
+ fn cause(&self) -> Option<&CargoError> {
+ self.cause.as_ref().map(|c| { let err: &CargoError = *c; err })
}
fn with_cause<E: CargoError + Send>(mut self,
self.detail.clone()
}
- fn cause(&self) -> Option<&CargoError + Send> {
- self.cause.as_ref().map(|c| { let err: &CargoError + Send = *c; err })
+ fn cause(&self) -> Option<&CargoError> {
+ self.cause.as_ref().map(|c| { let err: &CargoError = *c; err })
}
fn with_cause<E: CargoError + Send>(mut self,
from_error!(CliError)
+impl CargoError for docopt::Error {
+ fn description(&self) -> String {
+ match *self {
+ docopt::WithProgramUsage(ref other, _) => other.description(),
+ ref e if e.fatal() => self.to_string(),
+ _ => "".to_string(),
+ }
+ }
+
+ fn detail(&self) -> Option<String> {
+ match *self {
+ docopt::WithProgramUsage(_, ref usage) => Some(usage.clone()),
+ ref e if e.fatal() => None,
+ ref e => Some(e.to_string()),
+ }
+ }
+
+ fn is_human(&self) -> bool { true }
+}
+
+from_error!(docopt::Error)
+
impl CliError {
pub fn new<S: Str>(error: S, code: uint) -> CliError {
let error = human(error.as_slice().to_string());
if [ -z "${CFG_UNINSTALL}" ]
then
msg "verifying platform can run binaries"
- "${CFG_SRC_DIR}/bin/cargo" -h > /dev/null
+ "${CFG_SRC_DIR}/bin/cargo" -V > /dev/null
if [ $? -ne 0 ]
then
err "can't execute rustc binary on this platform"
if [ -z "${CFG_DISABLE_VERIFY}" ]
then
msg "verifying installed binaries are executable"
- "${CFG_DESTDIR}${CFG_PREFIX}/bin/cargo" -h > /dev/null
+ "${CFG_DESTDIR}${CFG_PREFIX}/bin/cargo" -V > /dev/null
if [ $? -ne 0 ]
then
ERR="can't execute installed rustc binary. "
test!(no_argument {
assert_that(cargo_process("cargo-new"),
execs().with_status(1)
- .with_stderr("must have a path as an argument\n"));
+ .with_stderr("Invalid arguments.
+Usage:
+ cargo-new [options] <path>
+ cargo-new -h | --help
+"));
})
test!(existing {